package com.haltakov.letterjumble.ui.components;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JComponent;

import com.haltakov.letterjumble.game.api.Letter;
import com.haltakov.letterjumble.game.api.Player;
import com.haltakov.letterjumble.ui.GraphicHelpers;

import static com.haltakov.letterjumble.ui.LookAndFeel.*;

@SuppressWarnings("serial")
public class PlayerLetters extends JComponent {

	private int width, height;
	private int minX, maxX, dx, dy, yThreshold;

	private static final Color LINE_COLOR = new Color(255, 255, 255);
	
	private static final int Y_FIRST = 10;
	private static final int Y_SECOND = 60;
	private static final int X_MARGIN = 10;

	private static final int GAP_SIZE = 10;
	private static final int SQUARE_SIZE = 30;

	private ArrayList<LetterBlock> letterBlocks;
	
	private int selectedLetterBlock = -1;
	
	private class LetterBlock {
		int width, height;
		int x, y;
		Letter letter;
		
		public LetterBlock(Letter letter, int x, int y) {
			this.letter = letter;
			this.x = x;
			this.y = y;
			width = SQUARE_SIZE;
			height = SQUARE_SIZE; 
		}
		
		public void paintBlock(Graphics g) {
			g.setColor(CELL_COLOR);
			g.fillRect(x, y, width, height);

			g.setColor(TEXT_COLOR);
			g.setFont(LETTER_FONT);
			
			GraphicHelpers.drawStringCentered(g, g.getFontMetrics(), letter.getCharacter().toString(), x, y, width, height);
			
			g.setFont(LETTER_POINTS_FONT);
			g.drawString("" + letter.getPoints(), x+width-6, y+height-2);
		}
	}

	public PlayerLetters () {
		letterBlocks = new ArrayList<LetterBlock>();
		
		minX = X_MARGIN;
		yThreshold = (Y_SECOND - Y_FIRST)/2 + Y_FIRST;
		
		addMouseListener(new MouseListener() {
			@Override
			public void mouseClicked(MouseEvent e) {
			}

			@Override
			public void mouseEntered(MouseEvent e) {}

			@Override
			public void mouseExited(MouseEvent e) {}

			@Override
			public void mousePressed(MouseEvent e) {
				for (LetterBlock lb: letterBlocks) {
					if (e.getX() >= lb.x && e.getX() <= (lb.x + lb.width) &&
						e.getY() >= lb.y && e.getY() <= (lb.y + lb.height)){
						selectedLetterBlock = letterBlocks.indexOf(lb);
						dx = lb.x - e.getX();
						dy = lb.y - e.getY();
					}
				}
			}

			@Override
			public void mouseReleased(MouseEvent e) {
				selectedLetterBlock = -1;
			}
		});
		
		addMouseMotionListener(new MouseMotionListener() {

			@Override
			public void mouseDragged(MouseEvent e) {
				if (selectedLetterBlock != -1) {
					LetterBlock lb = letterBlocks.get(selectedLetterBlock);
					
					lb.x = Math.min(maxX, Math.max(minX, e.getX()+dx));
					
					if (e.getY()+dy > yThreshold)
						lb.y = Y_SECOND;
					else
						lb.y = Y_FIRST;
					
					
					repaint();
				}
				
			}

			@Override
			public void mouseMoved(MouseEvent e) {}
			
		});
	}
	
	
	private void addLetter(Letter l) {
		int lastX = X_MARGIN - SQUARE_SIZE;
		
		if (!letterBlocks.isEmpty())
			lastX = letterBlocks.get(letterBlocks.size()-1).x;
		
		letterBlocks.add(new LetterBlock(l, lastX + GAP_SIZE + SQUARE_SIZE, Y_FIRST));
	}
	
	private void paintRow(Graphics g, ArrayList<LetterBlock> row) {
		for (LetterBlock lb: row)
			lb.paintBlock(g);
	}

	@Override
	public void paint(Graphics g) {
		Map<Object, Object> m = new HashMap<Object, Object>();
		m.put(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		((Graphics2D) g).addRenderingHints(m);
		
		maxX = getWidth()-X_MARGIN-SQUARE_SIZE;
		
		// Rows
		paintRow(g, letterBlocks);
		
		// Lines
		int x = X_MARGIN-5;
		int w = getSize().width - X_MARGIN + 5;

		g.setColor(LINE_COLOR);
		g.fillRect(x, Y_FIRST+SQUARE_SIZE+5, w, 3);
		g.fillRect(x, Y_SECOND+SQUARE_SIZE+5, w, 3);
		
	}

	@Override
	public void setPreferredSize(Dimension preferredSize) {
		width = preferredSize.width;
		height = preferredSize.height;
	}

	@Override
	public int getWidth() {
		return width;
	}

	@Override
	public int getHeight() {
		return height;
	}

	@Override
	public Dimension getPreferredSize() {
		return new Dimension(width, height);
	}
	
	public List<Letter> getWordLetters() {
		ArrayList<Letter> letters = new ArrayList<Letter>();
		
		Collections.sort(letterBlocks, new Comparator<LetterBlock>() {
			@Override
			public int compare(LetterBlock o1, LetterBlock o2) {
				return o1.x-o2.x;
			}
		});
		
		for (LetterBlock lb: letterBlocks) {
			if (lb.y == Y_SECOND)
				letters.add(lb.letter);
		}
		
		return Collections.unmodifiableList(letters);
	}


	public void changePlayer(Player newPlayer) {
		letterBlocks.clear();
		
		for (Letter l: newPlayer.getLetters())
			addLetter(l);
		
		repaint();
	}
}



